package com.maybach.workflow.core.config;


import com.maybach.workflow.common.api.FlowChain;
import com.maybach.workflow.common.api.enums.NodeTypeEnum;
import com.maybach.workflow.common.api.node.BaseNode;
import com.maybach.workflow.common.api.node.ForkNode;
import com.maybach.workflow.common.api.node.TaskNode;
import com.maybach.workflow.core.FlowDefineFactory;
import com.maybach.workflow.core.config.parser.NodeParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * Created by well on 15/6/9.
 */
public class Configuration implements InitializingBean{
    private static final Logger log = LoggerFactory.getLogger(Configuration.class);
    private List<String> flowDefineList;


    public static final String EXPRESSION_SPLIT_CHAR = ";";


    @Override
    public void afterPropertiesSet() throws Exception {
        this.config();
    }

    public void config(){
        NodeParser nodeParser = new NodeParser();
        for(String resource: flowDefineList){
            FlowChain parser = nodeParser.parser(resource);
            assemblyNode(parser);
            //assembleForkAndJoin(parser);
            // TODO 兼容无版本的流程
            if(!FlowDefineFactory.register(parser)) {

            }
        }

    }


    private void assemblyNode(FlowChain flowChain){
        Map<String, BaseNode> map = flowChain.getMap();
        Set<Map.Entry<String, BaseNode>> entries = map.entrySet();
        for(Map.Entry<String,BaseNode> entry:entries){
            BaseNode value = entry.getValue();
            if(value.getNodeType() == NodeTypeEnum.task ){
               if(((TaskNode)value).getUrl() == null){
                   log.warn("node config check  task url is null:"+value.getName());
               }
            }
            if(StringUtils.hasText(value.getParent()) && map.get(value.getParent()) == null){
                throw new RuntimeException("parent:" + value.getParent() + " undefine");
            }
            if(value.getTo() == null){
                continue;
            }
            BaseNode baseNode = map.get(value.getTo());
            if(baseNode == null){
                log.warn("node config check can not find task:"+value.getTo());
                continue;

            }
            if(! StringUtils.hasText(baseNode.getParent())){
                if(baseNode.getNodeType() == NodeTypeEnum.fork){
                    ForkNode forkNode = (ForkNode)baseNode;
                    for(BaseNode task:forkNode.getForkNodeList()){
                        if(task.getParent() == null) {
                            task.setParent(value.getName());
                        }
                    }
                }else {
                    baseNode.setParent(value.getTo());
                }
            }

        }
    }



    private String assemblyExpression(Map<String,String> paramMap){
        List<String> paramList = new ArrayList<String>(paramMap.keySet());
        Collections.sort(paramList);
        StringBuilder buf = new StringBuilder();
        for (int i = 0; i < paramList.size(); i++) {
            String key = paramList.get(i);
            String val = paramMap.get(key);
            if (i == paramList.size() - 1) {
                buf.append(key).append("=").append(val);
            } else {
                buf.append(key).append("=").append(val).append(";");
            }
        }
        return buf.toString();
    }

    public List<String> getFlowDefineList() {
        return flowDefineList;
    }

    public void setFlowDefineList(List<String> flowDefineList) {
        this.flowDefineList = flowDefineList;
    }
}
